package nci60.data.protein
import nci60.data.maxquant.Experiment
import nci60.data.maxquant.ExperimentClass
import nci60.data.connected.LeadingProtein
import nci60.data.connected.PeptideInProtein
import nci60.data.protein.uniprot.UniprotGOClass
import groovy.lang.GroovyShell
import java.text.DecimalFormat


/**
 * GRAILS <a href="http://grails.org/doc/latest/guide/theWebLayer.html#controllers" target="_blank">Controllers</a>
 * This controller handles all actions related to one single protein. <p />
 * It shows general information for a protein, as well as information about its identification, 
 * e.g. sequence coverage, protein expression, peptide identification and quantification and protein regulation between cell line groups. <p />
 * Additional it provides methods for generating plots for single proteins at the protein search and global expression analysis pages. <p />
 * If necessary a method for downloading this information is provided.
 *
 * @autor <a href="mailto:Florian.J.Auer@googlemail.com">Florian J. Auer</a>
*/
class ProteinController {

    /**
     * Makes the Query Service accessable
     * @see helper.QueryService
     */
    def queryService
        
    /**
     * Makes the Helper Service accessable
     * @see helper.HelperService
     */
    def helperService

    /**
     * redirects to the proteins action of the Query controller (proteins search page) as default entry point, because accessing this controller without specified protein makes no sense.
     */
    def index = {
        redirect(controller:'Query', action:'proteins')
    }


    /**
     * Entry action for showing one single protein. <p />
     * This action generates the html backbone for the protein page. The (other) single tabs of the page are called via AJAX. <p />
     * The page show only protein concerning information from IPI and uniprot. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def show = {
        //get the right protein with basic IPI information
        def result = Protein.findById(params?.id)
        //get full protein name from uniprot (if available)
        def protName
        result.uniprot.each(){
            protName = it.fullName
        }
        //get its gene ontology (GO) information from uniprot (if available)
        def goClasses = UniprotGOClass.findAll()
        def go = ['P':[], 'C':[], 'F':[], '?':[]]
        result.uniprot.each(){u->
            u.go.each(){
                go[it.goClass.letter.toString()].add(it)
            }
        }

        //check if protein is identified in enough cell lines and tissues per project to perform a expression analysis (and therefore show regulation tab)
        def showExpressionProfileTab = false
        def tmp = [:]
        Protein.executeQuery('select g.currentProject.id, g.experiment.currentClass.name, g.id from ProteinGroupExperiment g, LeadingProtein l where g.group=l.group and l.protein.id=:protein and g.lfqIntensity!=0', [protein:result.id]).each{line->
            def proj = line[0]
            def cls = line[1]
            if(tmp.containsKey(proj)){
               if(tmp[proj].nrWithTwoCels==2){showExpressionProfileTab=true}
            }else{
                tmp.put(proj, [nrWithTwoCels:0])
            }
            if(tmp[proj].containsKey(cls)){
                tmp[proj].nrWithTwoCels++
            }else{
                tmp[proj].put(cls, 0)
                tmp[proj].nrWithTwoCels++   //comment this line to set required cell lines per tissue to 2; with this line executed only one cell line per tissue is required 
            }
        }

        //get only one uniprot entry for displaying information
        def uniprot = null
        result.uniprot.eachWithIndex{ele,index->
            if(index==0){
                uniprot = ele
            }
        }

        //check if protein is identified, and therefore protein expression (and related actions) can be shown in tabs
        def projects = LeadingProtein.executeQuery('select count(l) from LeadingProtein l where l.protein.id='+params?.id)[0]

        return [Protein:result, Uniprot:uniprot, UniprotName:protName, GO:go, GOClasses:goClasses, Projects:projects, ShowExpressionProfileTab:showExpressionProfileTab]
    }

    /**
     * Returns the amio acid sequence of the protein with the identified peptide regions highlighted for each project. <p />
     * The action is called via AJAX and the results are rendered by GJP <p />
     * Uses {@link #formatSequenceHTML} for masking peptides and generating html <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def showSequence = {
        //get the right protein
        def result = Protein.findById(params?.id)
        //get the projects with peptide identifications
        def projects = PeptideInProtein.executeQuery('select distinct p.currentProject from PeptideInProtein p where p.protein.id='+params?.id)
        
        //get all identified peptides for this protein and mark them in the protein sequence
        //peptides[projectId]=PeptideInProtein
        def peptides = [:]
        //calculate sequence coverage for each project
        //coverage[projectId]=sequence coverage in %
        def coverage = [:]
        projects.each(){proj->
            peptides.put(proj, PeptideInProtein.executeQuery('select p from PeptideInProtein p where p.protein.id='+params?.id+' and p.currentProject.id='+proj.id))
            def temp = []   //length of the protein sequence, initialized with "false" entrys
            result.sequence.each(){temp.add(false)}
            //set the identified aa in the protein (temp) to "true"
            peptides[proj].each(){p->
                for(i in (p.position)..(p.position + (p.peptide.sequence.size()-1))) {temp[i] = true}
            }
            //count the "true" values to get coverage and avoid double counting of overlaping peptides
            def count = 0
            temp.each(){if(it==true){count++}}
            coverage.put(proj, ((count*100)/result.sequence.size()).toInteger())
        }
        //mask the identified peptides in the protein seuqence and return the result as html
        def seq = formatSequenceHTML(result.sequence, peptides)
        
        render(template:"showSequence", model:[Seq:seq, SeqLength:result.sequence.size(), Weight:result.weight, Projects:projects, Protein:params.id, Coverage:coverage])
    }

    /**
     * Returns the amio acid sequence of the protein in fasta format. <p />
     * The action is called via AJAX and the results are returned as file. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def downloadSequence = {
        def result = Protein.findById(params?.id)
        def desc = (result.uniprot!=null) ? result.uniprot.fullName : result.description
        def head = '>'+result.mainId+'|'+result.organism.name+'|'+desc

        def lines = []
        def line = ''
        int counter = 0
        result.sequence.each(){
            counter++
            line+=it
            if(counter%60==0){
                lines.add(line)
                line = ''
            }
        }
        if(counter%60!=0){
            lines.add(line)
        }

        response.setContentType("text/plain")
        response.setHeader("Content-disposition", "filename=${result.mainId+'_fasta.txt'}")
        response.outputStream << head+'\n'
        lines.each(){
            response.outputStream <<  it+'\n'
        }
        response.outputStream.flush()
        return response
    }

    /**
     * Shows a schematic representation of the identified peptides aligned to the protein (aka Peptide Map) <p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def showSequenceCoverage = {
        def seqLength = Protein.findById(params?.id).sequence.size()
        def projects = LeadingProtein.executeQuery('select distinct i.currentProject from LeadingProtein i where i.protein.id='+params?.id)
        def result = [:]
        projects.each(){proj->
            def expLine = [:]
            def experiments = Experiment.findAllByCurrentProject(proj)
            experiments.each(){exp->
                def peptidesLine = []
                expLine.put(exp.name, peptidesLine)
            }
            result.put(proj, expLine)
        }
        def foundPeptides = PeptideInProtein.executeQuery('select p from PeptideInProtein p where p.peptide.contaminant=false and p.peptide.reverse=false and p.protein='+params?.id)
        def maxIntensity = 0
        def minIntensity = Double.MAX_VALUE
        foundPeptides.each(){f->
            if(f.peptide.missedCleavages==0){
                def pos = f.position
                def seq = f.peptide.sequence
                def mass = f.peptide.mass
                def uniqG = f.peptide.uniqueGroups
                def uniqP = f.peptide.uniqueProteins
                def razor = f.razor
                def id = f.peptide.id
                f.peptide.experiments.each(){expPep->
                    if((result[f.peptide.currentProject]!=null)&&(result[f.peptide.currentProject][expPep.experiment.name]!=null)){
                        def intensity = expPep.intensity
                        maxIntensity = (intensity>maxIntensity)?intensity:maxIntensity
                        minIntensity = (intensity<minIntensity)?intensity:minIntensity
                        result[f.peptide.currentProject][expPep.experiment.name].add([Start:pos, End:(pos+seq.size()-1), Seq:seq, Mass:mass, UniqG:uniqG, UniqP:uniqP , Razor:razor, Intensity:intensity, Id:id, Cellline:expPep.experiment.id, Cls:expPep.experiment.currentClass.id])
                    }
                }
            }
        }

        render(template:"showSequenceCoverage", model:[SeqLength:seqLength, Projects:result, MaxIntensity:maxIntensity, MinIntensity:minIntensity])
    }

    /**
     * Lets download the expression of the protein in the different cell lines and projects <p />
     * The action is called via AJAX and the returned as file. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def showProteinExpression = {
        //allCelllines[projectId].nrCelllines=NrOfCelllinesInProject
        //                       .cls[clsId].show=false
        //                                  .celllines[celllineId].name=celllineName
        //                                                        .show=false
        def allCelllines = [:]
        Protein.executeQuery('select e.currentProject.id, e.currentClass.id, e.id, e.name from Experiment e').each{line->
            def proj = line[0]
            def cls = line[1]
            def celId = line[2]
            def celName = line[3]
            if(!allCelllines.containsKey(proj)){allCelllines.put(proj, [nrCelllines:0, cls:[:]])}
            if(!allCelllines[proj].cls.containsKey(cls)){allCelllines[proj].cls.put(cls, [celllines:[:], show:false])}
            allCelllines[proj].cls[cls].celllines.put(celId, [name:celName, show:false])
            allCelllines[proj].nrCelllines++
        }

        //data[project].name=projectName
        //             .avg=ProjectAverageOfIntensities
        //             .max=ProjectMaxIntensity
        //             .nrCelllines=NrOfCelllinesInProject
        //             .cls[CellLineClassId].name=CellLineClassName
        //                                  .avg=CellLineClassAverageOfIntensities
        //                                  .celllines[CellLineId].intensity=Intensity
        //                                                        .unique=NrOfUniquePeptides
        //                                                        .msmsCount=SpectralCount
        def data = [:]
        Protein.executeQuery('select l.group, e.experiment, e.lfqIntensity, e.msmsCount from LeadingProtein l, ProteinGroupExperiment e where e.group=l.group and e.lfqIntensity!=0 and l.protein.id='+params?.id).each{line->
            def group = line[0]
            def cellline = line[1]
            def intensity = line[2]
            def msmsCount = line[3]
            if(!data.containsKey(group.currentProject.id)){data.put(group.currentProject.id, [name:group.currentProject.name, cls:[:], nrCelllines:0])}
            if(!data[group.currentProject.id].cls.containsKey(cellline.currentClass.id)){data[group.currentProject.id].cls.put(cellline.currentClass.id, [name:cellline.currentClass.name, celllines:[:]])}
            data[group.currentProject.id].cls[cellline.currentClass.id].celllines.put(cellline.id, [intensity:intensity, unique:0, msmsCount:msmsCount])
            data[group.currentProject.id].nrCelllines++
            allCelllines[group.currentProject.id].cls[cellline.currentClass.id].show=true
            allCelllines[group.currentProject.id].cls[cellline.currentClass.id].celllines[cellline.id].show=true
        }
        data.each{projId,projValues->
            def projAvg = 0
            def projCount = 0
            def max = 0
            projValues.cls.each{clsId,clsValues->
                def clsAvg = 0
                clsValues.celllines.each{celId,celValues->
                    max = (max<celValues.intensity) ? celValues.intensity : max
                    clsAvg = clsAvg + celValues.intensity
                }
                clsValues.put('avg', (clsAvg/clsValues.celllines.size()))
                projAvg = projAvg + clsAvg
                projCount = projCount + clsValues.celllines.size()
            }
            projValues.put('avg', (projAvg/projCount))
            projValues.put('max', max)
        }

        PeptideInProtein.executeQuery('select p.peptide from PeptideInProtein p where p.peptide.uniqueGroups=true and p.protein.id='+params.id).each(){p->
            if((data.containsKey(p.currentProject.id))){
                p.experiments.each(){e->
                    if((data[p.currentProject.id].cls.containsKey(e.experiment.currentClass.id))&&(data[p.currentProject.id].cls[e.experiment.currentClass.id].celllines.containsKey(e.experiment.id))){
                        data[p.currentProject.id].cls[e.experiment.currentClass.id].celllines[e.experiment.id].unique++
                    }
                }
            }
        }

        def colors = helperService.getParameters('celllinecolors').celllinecolors

        render(template:"showProteinExpression", model:[Projects:data, AllCelllines:allCelllines, Colors:colors, Download:params.id])
    }


    /**
     * Shows the expression of the protein in the different cell lines and projects <p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def downloadProteinExpression = {
        def data = [:]
        Protein.executeQuery('select l.group, e.experiment, e.lfqIntensity, e.msmsCount from LeadingProtein l, ProteinGroupExperiment e where e.group=l.group and e.lfqIntensity!=0 and l.protein.id='+params?.id).each{line->
            def group = line[0]
            def cellline = line[1]
            def intensity = line[2]
            def msmsCount = line[3]
            if(!data.containsKey(group.currentProject.id)){data.put(group.currentProject.id, [name:group.currentProject.name, cls:[:]])}
            if(!data[group.currentProject.id].cls.containsKey(cellline.currentClass.id)){data[group.currentProject.id].cls.put(cellline.currentClass.id, [name:cellline.currentClass.name, celllines:[:]])}
            data[group.currentProject.id].cls[cellline.currentClass.id].celllines.put(cellline.id, [name:cellline.name, intensity:intensity, unique:0, msmsCount:msmsCount])
        }
        data.each{projId,projValues->
            def projAvg = 0
            def projCount = 0
            def max = 0
            projValues.cls.each{clsId,clsValues->
                def clsAvg = 0
                clsValues.celllines.each{celId,celValues->
                    max = (max<celValues.intensity) ? celValues.intensity : max
                    clsAvg = clsAvg + celValues.intensity
                }
                clsValues.put('avg', (clsAvg/clsValues.celllines.size()))
                projAvg = projAvg + clsAvg
                projCount = projCount + clsValues.celllines.size()
            }
            projValues.put('avg', (projAvg/projCount))
            projValues.put('max', max)
        }

        PeptideInProtein.executeQuery('select p.peptide from PeptideInProtein p where p.peptide.uniqueGroups=true and p.protein.id='+params.id).each(){p->
            if((data.containsKey(p.currentProject.id))){
                p.experiments.each(){e->
                    if((data[p.currentProject.id].cls.containsKey(e.experiment.currentClass.id))&&(data[p.currentProject.id].cls[e.experiment.currentClass.id].celllines.containsKey(e.experiment.id))){
                        data[p.currentProject.id].cls[e.experiment.currentClass.id].celllines[e.experiment.id].unique++
                    }
                }
            }
        }

        response.setContentType("text/csv")
        response.setHeader("Content-disposition", "filename=${'ProteinExpression.csv'}")
        response.outputStream << 'Cell Line;Expression;Unique Peptides;Spectral Count\n'
        data[params.project.toInteger()].cls.each{clsId,clsValues->
            clsValues.celllines.each{celId,celValues->
                response.outputStream << celValues.name+';'+celValues.intensity.toInteger()+';'+celValues.unique+';'+celValues.msmsCount+'\n'
            }
        }
        response.outputStream.flush()
        return response
    }



    /**
     * Maskes the peptides in the protein seuquence and returns it as html<p />
     * Helping closure, which is used in {@link #showSequence}. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              String seq
     * </td><td>        amino acid sequence of the protein
     * </td></tr>
     * <tr><td class="z">
     *              Map<projectId:List<PeptideInProtein>> pep
     * </td><td>        Map from project id to a list of corresponding peptides (as PeptideInProtein)
     * </td></tr>
     * </table>
     * <p /><p />
     * 
     * Return: <p />
     * 
     * <table class="custom-table">
     * <tr><td class="z">
     *              String
     * </td><td>        HTML representation of the protein sequence with within marked aa for each peptide and project
     * </td></tr>
     * </table>
     */
    def formatSequenceHTML = {seq,pep ->
        def ranges = [:]
        pep.each(){proj, peptides->
            def tmp = []
            seq.each(){tmp.add(false)}
            peptides.each(){p->
                def start = p.position
                def end = start + (p.peptide.sequence.size()-1)
                for(i in start..end) {
                    tmp[i] = true
                }
            }
            ranges.put(proj, tmp)
        }


        def seqClasses = [:]
        seq.eachWithIndex(){s,i->
            def temp = []
            seqClasses.put(i, temp)
        }


        ranges.each(){proj, range->
            range.eachWithIndex(){r,i->
                if(r){
                    seqClasses[i].add("proj"+proj.id)
                }
            }
        }

        def modSeq = [:]
        seq.eachWithIndex(){s,i->
            modSeq.put(i, s)
        }

        modSeq.each(){i,s->
            if(seqClasses[i].size()!=0){
                def classes = ""
                seqClasses[i].each(){c->
                    classes = classes+" "+c
                }
                modSeq[i] = "<div class=\"marked"+classes+"\" >"+modSeq[i]+"</div>"
            }

            if(i%10==0){
                modSeq[i] = "<div class=\"block\">"+modSeq[i]
            }
            if(((i+1)%10==0)||((i+1)==modSeq.size())){
                modSeq[i] = modSeq[i]+"</div>"
            }

            if(i%60==0){
                modSeq[i] = "<div class=\"sequence\"><div class=\"lineNumber\">"+(i+1)+"</div>"+modSeq[i]
            }
            if(((i+1)%60==0)||((i+1)==modSeq.size())){
                modSeq[i] = modSeq[i]+"</div>\n"
            }
        }

        def result = ""
        modSeq.each(){i,s->
            result = result+s
        }

        return result
    }

    /**
     * Shows the detailed protein expression in global expression analysis. <p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              protein
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * <tr><td class="z">
     *              cellline
     * </td><td>        cell line group (tissue) on which was clicked
     * </td></tr>
     * <tr><td class="z">
     *              refLine
     * </td><td>        cell line group (tissue) which served as reference for calculating up and down regulation <p />
     *                  "avg" if the average over the cell lines is used.
     * </td></tr>
     * <tr><td class="z">
     *              celllines
     * </td><td>        List of cell line groups (tissues) used for calcualtion
     * </td></tr>
     * <tr><td class="z">
     *              pValues
     * </td><td>        Map<projectID:pValue> <p />
     *                  Gives the corrected p-values to each project. <p />
     *                  This is necessary, because new calculation would take too long. 
     * </td></tr>
     * <tr><td class="z">
     *              up
     * </td><td>        Gives a boolean value if the project where the clicked cell line groups (tissues) is up-regulated should be shown
     * </td></tr>
     * <tr><td class="z">
     *              down
     * </td><td>        Gives a boolean value if the project where the clicked cell line groups (tissues) is down-regulated should be shown
     * </td></tr>
     * <tr><td class="z">
     *              non
     * </td><td>        Gives a boolean value if the project where the clicked cell line groups (tissues) is non-regulated should be shown
     * </td></tr>
     * </table>
     */
    def expressionPlots = {
        def selectedCellline = params.cellline
        def queryCelllines = params.celllines.replaceAll('\\[', '').replaceAll('\\]', '').split(', ')
        def refLine = params.refLine
        def groupPValues = new GroovyShell().evaluate(params.pValues)
        def up = params.up.toBoolean()
        def down = params.down.toBoolean()
        def non = params.non.toBoolean()

        def data = [:]
        def nonRegulated = 0
        def upRegulated = 0
        def downRegulated = 0
        def protein = Protein.findById(params.protein)

        def newParams = [celllines:queryCelllines, pValues:params.pValues, up:params.up, down:params.down, non:params.non, protein:params.protein]

        Protein.executeQuery('select g.currentProject.id, g.currentProject.name, g.experiment.currentClass.name, g.experiment.name, g.lfqIntensity from ProteinGroupExperiment g, LeadingProtein l where g.group=l.group and l.protein.id=:protein and l.currentProject.id in :proj and g.experiment.currentClass.name in :exp and g.experiment.excluded=false and g.lfqIntensity!=0', [proj:groupPValues.keySet(), exp:queryCelllines, protein:protein.id]).each(){line->
            def groupId = line[0].toString()
            def groupName = line[1]
            def clsId = line[2]
            def expId = line[3]
            def intensity = line[4]
            if(!data.containsKey(groupId)){data.put(groupId,[name:groupName, cls:[:], pValue:groupPValues[groupId.toInteger()]])}
            if(!data[groupId].cls.containsKey(clsId)){data[groupId].cls.put(clsId,[exps:[], intensities:[]])}
            data[groupId].cls[clsId].exps.add(expId)
            data[groupId].cls[clsId].intensities.add(intensity)
        }

        DecimalFormat df = new DecimalFormat( "0.00E0" )
        def result = []
        data.each{group, groupValues->
            if(groupValues.cls.containsKey(selectedCellline)){
                def addGroup = false
                def tmp_result = [name:groupValues.name, pValue:groupValues.pValue, pValueF:df.format(groupValues.pValue.toDouble()), cls:[:]]
                def tmp_Avg = 0
                def tmpAvgCount = 0
                def tmp_maxIntensity = 0
                groupValues.cls.each{cls, clsValues->
                    tmp_result.cls.put(cls, [intensities:clsValues.intensities, exps:clsValues.exps])
                    def tmp_clsAvg = 0
                    clsValues.intensities.each{intens->
                        tmp_clsAvg = tmp_clsAvg + Math.log10(intens)
                        tmp_maxIntensity = (tmp_maxIntensity>=intens)?tmp_maxIntensity:intens
                    }
                    tmp_Avg = tmp_Avg + tmp_clsAvg
                    tmpAvgCount = tmpAvgCount + clsValues.intensities.size()
                    tmp_result.cls[cls].put('avg', (tmp_clsAvg/clsValues.intensities.size()))
                }
                tmp_result.put('avg', (tmp_Avg/tmpAvgCount))
                tmp_result.put('max', tmp_maxIntensity)
                tmp_result.put('nrOfCelllines', tmpAvgCount)
                if(tmp_result.pValue<=0.05){
                    def tmp_refAvg = (refLine=='avg')?tmp_result.avg:tmp_result.cls[refLine].avg
                    tmp_result.cls.each{cls, clsValues->
                        clsValues.put('regulation', (((Math.log10(clsValues.avg/tmp_refAvg)/Math.log10(2))*100000).toInteger()/100000))
                        if(up&&(clsValues.regulation>=0)&&(cls==selectedCellline)){
                            upRegulated++
                            addGroup = true
                        }else if(down&&(clsValues.regulation<0)&&(cls==selectedCellline)){
                            downRegulated++
                            addGroup = true
                        }
                    }
                }
                if(non&&(tmp_result.pValue>0.05)&&(tmp_result.cls.containsKey(selectedCellline))){
                    addGroup = true
                    nonRegulated++
                }
                if(addGroup){result.add(tmp_result)}
            }
        }

        def colors = helperService.getParameters('celllinecolors').celllinecolors
        render(template:'expressionPlots', model:[Projects:result, Non:nonRegulated, Up:upRegulated, Down:downRegulated, RefLine:refLine, Protein:protein, Cellline:selectedCellline, Colors:colors, NewParams:newParams])
    }

    
    /**
     * Shows the expression of the protein in the different cell lines and projects in the protein search page.<p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def simpleExpressionPlots = {

        def data = [:]
        def protein = Protein.findById(params.id)

        Protein.executeQuery('select g.currentProject.id, g.currentProject.name, g.experiment.currentClass.name, g.experiment.name, g.lfqIntensity from ProteinGroupExperiment g, LeadingProtein l where g.group=l.group and l.protein.id=:protein and g.lfqIntensity!=0', [protein:protein.id]).each(){line->
            def groupId = line[0].toString()
            def groupName = line[1]
            def clsId = line[2]
            def expId = line[3]
            def intensity = line[4]
            if(!data.containsKey(groupId)){data.put(groupId,[name:groupName, cls:[:]])}
            if(!data[groupId].cls.containsKey(clsId)){data[groupId].cls.put(clsId,[exps:[], intensities:[]])}
            data[groupId].cls[clsId].exps.add(expId)
            data[groupId].cls[clsId].intensities.add(intensity)
        }

        DecimalFormat df = new DecimalFormat( "0.00E0" )
        def result = []
        data.each{group, groupValues->
            def addGroup = false
            def tmp_result = [name:groupValues.name, cls:[:]]
            def tmp_Avg = 0
            def tmpAvgCount = 0
            def tmp_maxIntensity = 0
            groupValues.cls.each{cls, clsValues->
                tmp_result.cls.put(cls, [intensities:clsValues.intensities, exps:clsValues.exps])
                def tmp_clsAvg = 0
                clsValues.intensities.each{intens->
                    tmp_clsAvg = tmp_clsAvg + Math.log10(intens)
                    tmp_maxIntensity = (tmp_maxIntensity>=intens)?tmp_maxIntensity:intens
                }
                tmp_Avg = tmp_Avg + tmp_clsAvg
                tmpAvgCount = tmpAvgCount + clsValues.intensities.size()
                tmp_result.cls[cls].put('avg', (tmp_clsAvg/clsValues.intensities.size()))
            }
            tmp_result.put('avg', (tmp_Avg/tmpAvgCount))
            tmp_result.put('max', tmp_maxIntensity)
            tmp_result.put('nrOfCelllines', tmpAvgCount)
            result.add(tmp_result)
        }
        def colors = helperService.getParameters('celllinecolors').celllinecolors
        render(template:'simpleExpressionPlots', model:[Projects:result, Protein:protein, Colors:colors])
    }


    /**
     * Shows a list of all identified peptides <p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def peptides = {
        def peptides = PeptideInProtein.executeQuery('select p from PeptideInProtein p where p.peptide.contaminant=false and p.peptide.reverse=false and p.protein.id='+params.id)
        def aaBeforeAndAfter = []
        peptides.each(){pep->
            def bef = ''
            if(pep.position>0){bef = pep.protein.sequence[pep.position-1].toUpperCase()+'.'}
            def after = ''
            if(pep.protein.sequence.size()>(pep.position+pep.peptide.sequence.size())){after = '.'+pep.protein.sequence[pep.position+pep.peptide.sequence.size()].toUpperCase()}
            aaBeforeAndAfter.add([before:bef, after:after])
        }
        render(template:'peptides', model:[Peptides:peptides, Download:params.id, AABeforeAndAfter:aaBeforeAndAfter, Protein:params.id])
    }

    /**
     * Lets download a list of all identified peptides <p />
     * The action is called via AJAX and the returned as file. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def downloadPeptides = {
        def peptides = PeptideInProtein.executeQuery('select p from PeptideInProtein p where p.peptide.contaminant=false and p.peptide.reverse=false and p.protein.id='+params.id)

        response.setContentType("text/csv")
        response.setHeader("Content-disposition", "filename=${'Peptides.csv'}")
        response.outputStream << 'Sequence;Mass[Da];Position;Length;Missed Cleavages;Razor;Unique (Groups);Unique (Proteins);Best Score;PEP;Intensity;Experiment\n'
        peptides.each(){p->
            def seq = p.peptide.sequence
            seq = (p.position>0)?p.protein.sequence[p.position-1].toUpperCase()+'.'+seq:seq
            seq = (p.protein.sequence.size()>(p.position+p.peptide.sequence.size()))?seq+'.'+p.protein.sequence[p.position+p.peptide.sequence.size()].toUpperCase():seq
            response.outputStream << seq+';'+p.peptide.mass+';'+p.position+';'+p.peptide.sequence.size()+';'+p.peptide.missedCleavages+';'+p.razor+';'+p.peptide.uniqueGroups+';'+p.peptide.uniqueProteins+';'+p.peptide.score+';'+p.peptide.pep+';'+p.peptide.intensity+';'+p.currentProject.name+'\n'
        }
        response.outputStream.flush()
        return response
    }

    /**
     * Entry action for showing MsMs spectra. <p />
     * Only renders the select boxes. The setted values are preset, if redirected from an other tab.
     * After page is loaded, {@link #showLorikeet} is called via javascript and ajax.
     * Lorikeet is initialized by java script after new content is loaded. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * <tr><td class="z">
     *              project
     * </td><td>        project id (dataset/experiment) <p />
     *                  <b>(optional)</b>
     * </td></tr>
     * <tr><td class="z">
     *              peptide
     * </td><td>        peptide id <p />
     *                  <b>(optional)</b>
     * </td></tr>
     * <tr><td class="z">
     *              cls
     * </td><td>        cell line group id (tissue of origin/cell line class) <p />
     *                  <b>(optional)</b>
     * </td></tr>
     * <tr><td class="z">
     *              cel
     * </td><td>        cell line id <p />
     *                  <b>(optional)</b>
     * </td></tr>
     * </table>
     */
    def showMsMsSpectra = {
        def defaultSelected = [:]
        defaultSelected.put('project', (params.project!=null)?params.project.toLong():'')
        defaultSelected.put('cls', (params.cls!=null)?params.cls.toLong():'')
        defaultSelected.put('cellline', (params.cel!=null)?params.cel.toLong():'')
        defaultSelected.put('peptide', (params.peptide!=null)?params.peptide.toLong():'')
        def projects = [:]
        def cls = [:]
        def cel = [:]
        def celToCls = [:]
        Experiment.executeQuery('select e.id, e.name, e.currentClass.id, e.currentClass.name, e.currentProject.id, e.currentProject.name from Experiment e').each{line->
            projects.put(line[4], line[5])
            cls.put(line[2], line[3])
            cel.put(line[0], line[1])
            celToCls.put(line[0], line[2])
        }
        def rawFiles = [:]
        Experiment.executeQuery('select r.id, r.name from RawFile r').each{line->
            rawFiles.put(line[0], line[1])
        }
        
        def peptides = [:]
        PeptideInProtein.executeQuery('select p.currentProject.id, p.peptide.id, p.peptide.sequence from PeptideInProtein p where p.peptide.contaminant=false and p.peptide.reverse=false and p.protein=p.peptide.leadingRazorProtein and p.protein.id='+params.id).each{line->
            def projId = line[0]
            def pepId = line[1]
            def pepSeq = line[2]
            peptides.put(pepId, pepSeq)
        }

        def data = [:]
        Experiment.executeQuery('select m.currentProject.id, m.peptide.id, m.experiment.id, m.rawFile.id, m.score, m.id from MsMs m where m.peptide.id in :peptides group by m.currentProject.id, m.peptide.id, m.experiment.id, m.rawFile.id', [peptides:peptides.keySet()]).each{line->
            def proj = line[0]
            def pep = line[1]
            def cellline = line[2]
            def celClass = celToCls[cellline]
            def raw = line[3]
            def score = line[4]
            def id = line[5]
            if(!data.containsKey(proj)){data.put(proj, [:])}
            if(!data[proj].containsKey(pep)){data[proj].put(pep, [:])}
            if(!data[proj][pep].containsKey(celClass)){data[proj][pep].put(celClass, [:])}
            if(!data[proj][pep][celClass].containsKey(cellline)){data[proj][pep][celClass].put(cellline, [:])}
            if(!data[proj][pep][celClass][cellline].containsKey(raw)){data[proj][pep][celClass][cellline].put(raw, [:])}
            data[proj][pep][celClass][cellline][raw].put(id, score)
        }

        render(template:'showMsMsSpectra', model:[Select:data, Projects:projects, Peptides:peptides, Cls:cls, Celllines:cel, RawFiles:rawFiles, DefaultSelected:defaultSelected])
    }


    /**
     * Showing a MsMs spectra. <p />
     * The action is called via AJAX and the rendered via GSP. Javascript starts Lorikeet.<p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * <tr><td class="z">
     *              msProject <b>or</b> msHiddenProject
     * </td><td>        project id (dataset/experiment)
     * </td></tr>
     * <tr><td class="z">
     *              msPeptide
     * </td><td>        peptide id
     * </td></tr>
     * <tr><td class="z">
     *              msCls
     * </td><td>        cell line group id (tissue of origin/cell line class)
     * </td></tr>
     * <tr><td class="z">
     *              msCellline
     * </td><td>        cell line id
     * </td></tr>
     * <tr><td class="z">
     *              msRawFile
     * </td><td>        raw file id
     * </td></tr>
     * </table>
     */
    def showLorikeet = {
        def projectId = (params.msProject!=null)?params.msProject.toInteger():params.msHiddenProject.toInteger()
        def peptideId = params.msPeptide.toLong()
        def cslId = params.msCls.split('_')[-1].toInteger()
        def celllineId = params.msCellline.split('_')[-1].toInteger()
        def rawFileId = params.msRawFile.split('_')[-1].toInteger()

        def maxScore = Experiment.executeQuery('select max(m.score) from MsMs m where m.currentProject.id=:proj and m.peptide.id=:pep and m.experiment.id=:cel and m.rawFile.id='+rawFileId, [proj:projectId, pep:peptideId, cel:celllineId])[0]
        def msms = Experiment.executeQuery('select m from MsMs m where m.currentProject.id=:proj and m.peptide.id=:pep and m.experiment.id=:cel and m.rawFile.id='+rawFileId+' and m.score=:score', [proj:projectId, pep:peptideId, cel:celllineId, score:maxScore])[0]

        def charge = msms.charge
        def scanNumber = msms.scanNumber
        def sequence = msms.sequence
        def rawFile = msms.rawFile.name
        def precursorMZ = msms.precursorMZ
        def oxi = []
        msms.oxidations.split(';').each{
            if(it!=''){oxi.add(it.toInteger()+1)}
        }
        def acetylation = msms.acetylation

        def tmp_peak = Experiment.executeQuery('select fs.masses, fs.intensities from FullSpectrum fs where fs.currentProject.id=:proj and fs.scanNumber=:scan and fs.rawFile=:raw', [proj:projectId, raw:msms.rawFile, scan:scanNumber])[0]

        def masses = tmp_peak[0].split(';')
        def intensities = tmp_peak[1].split(';')

        def peaks = []
        masses.eachWithIndex{m,index->
            peaks.add([m.toDouble(), intensities[index]])
        }
        peaks = peaks.sort{it[0]}
        peaks.add([(peaks[-1][0]+(peaks[0][0]*0.05)),0])
        peaks.add([(peaks[0][0]*0.95),0])

        render(template:'showLorikeet', model:[Charge:charge, ScanNumber:scanNumber, Seq:sequence, RawFile:rawFile, PrecursorMZ:precursorMZ, Peaks:peaks, Oxidations:oxi, Acetylation:acetylation])
    }


    /**
     * Entry action for comparative expression. <p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * Only the cell line selection is rendered. Javascript calls {@link #showProteinRegulation} via AJAX when content is loaded. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              id
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * </table>
     */
    def showProteinRegulation = {
        def celllines = Protein.executeQuery('select distinct g.experiment.currentClass.name from ProteinGroupExperiment g, LeadingProtein l where g.group=l.group and l.protein.id=:protein and g.lfqIntensity!=0', [protein:params.id.toLong()])
        render(template:"showProteinRegulation", model:[Celllines:celllines, Protein:params.id])
    }

    /**
     * Entry action for comparative expression. <p />
     * The action is called via AJAX and the rendered via GSP. <p />
     * Only the cell line selection is rendered. Javascript calls {@link #showProteinRegulation} via AJAX when content is loaded. <p />
     * <p />
     * 
     * Parameter (params): <p />
     * 
     * <style>.custom-table td{border-top:1pt solid grey;vertical-align:top;} .custom-table{border-collapse:collapse;width:100%;} .custom-table .z{background-color:rgb(230, 230, 230);}</style>
     * <table class="custom-table">
     * <tr><td class="z">
     *              protein
     * </td><td>        id of the protein in the IPI domain class. <p />
     *                  This is not the IPI identifier, but the id in the database!
     * </td></tr>
     * <tr><td class="z">
     *              refLine
     * </td><td>        used reference cell line group or "avg" for average over all groups
     * </td></tr>
     * <tr><td class="z">
     *              [cell line group]
     * </td><td>        each cell line group, which should be included for the analysis has to be add to the params by name.
     *                  e.g. "COLON" is add as params.COLON <p/>
     *                  Doing it this way is dependent on javascript.
     * </td></tr>
     * </table>
     */
    def getRegulationResults = {
        //get the wanted (queried) Celllines
        def queryCelllines = []
        def allCelllinesFound = true
        ExperimentClass.executeQuery('select distinct c.name from ExperimentClass c').each(){
            if(params[it]!=null){queryCelllines.add(it)}else{allCelllinesFound=false}
        }
        def refLine = params.refLine

        def protein = Protein.findById(params.protein)
        //data[projectId].name=projectName
        //               .cls[CelllineClassName].exps[]=CelllineName
        //                                      .intensities[]=CelllineIntensity
        def data = [:]

        def result = []
        def nonRegulated = 0
        def upRegulated = 0
        def downRegulated = 0

        if(queryCelllines.size()>1){
            Protein.executeQuery('select g.currentProject.id, g.currentProject.name, g.experiment.currentClass.name, g.experiment.name, g.lfqIntensity from ProteinGroupExperiment g, LeadingProtein l where g.group=l.group and l.protein.id=:protein and g.experiment.currentClass.name in :exp and g.lfqIntensity!=0', [exp:queryCelllines, protein:protein.id]).each(){line->
                def groupId = line[0].toString()
                def groupName = line[1]
                def clsId = line[2]
                def expId = line[3]
                def intensity = line[4]
                if(!data.containsKey(groupId)){data.put(groupId,[name:groupName, cls:[:]])}
                if(!data[groupId].cls.containsKey(clsId)){data[groupId].cls.put(clsId,[exps:[], intensities:[]])}
                data[groupId].cls[clsId].exps.add(expId)
                data[groupId].cls[clsId].intensities.add(intensity)
            }

            def pValues = [:]
            if(false){
                Protein.executeQuery('select d.currentProject.id, d.pValue from DefaultPValue d where d.protein.id=:protein', [protein:protein.id]).each{line->
                    def proj = line[0].toString()
                    def pVal = line[1]
                    pValues.put(proj, pVal)
                }
            }else{
                //clsCounts[projectId][CelllineGroup]=NrOfCelllinesInGroup
                def clsCounts = [:]
                ExperimentClass.executeQuery('select e.currentProject.id, e.currentClass.name, count(e.id) from Experiment e where e.excluded=false and e.currentClass.name in :cls group by e.currentProject.id, e.currentClass.name having count(e.id)>1', [cls:queryCelllines]).each(){line->
                    def proj = line[0]
                    if(!clsCounts.containsKey(proj)){clsCounts.put(proj, [:])}
                    clsCounts[proj].put(line[1], line[2])
                }


                //get Data from DB; data[projectId][ProteinId][CelllineGroup][CelllineId]=Intensity
                def tmp_data = queryService.getData(queryCelllines, clsCounts.keySet() as List)

                //pValues[projectID][ProteinId]=pValue
                def tmp_pValues = queryService.generatePValues(tmp_data, queryCelllines, clsCounts)

                //qValues[projectID][ProteinId]=qValue
                def qValues = queryService.generateQValues(tmp_pValues)
                qValues.each{proj,projVal->
                    pValues.put(proj.toString(), projVal[protein.id.toString()])
                }
            }

            Locale.setDefault(new Locale("US"));
            DecimalFormat df = new DecimalFormat( "0.00E0" )

            data.each{group, groupValues->
                    def tmp_result = [name:groupValues.name, pValue:pValues[group], pValueF:((pValues[group]!=null)?df.format(pValues[group]):''), cls:[:]]
                    def tmp_Avg = 0
                    def tmpAvgCount = 0
                    def tmp_maxIntensity = 0
                    groupValues.cls.each{cls, clsValues->
                        tmp_result.cls.put(cls, [intensities:clsValues.intensities, exps:clsValues.exps])
                        def tmp_clsAvg = 0
                        clsValues.intensities.each{intens->
                            tmp_clsAvg = tmp_clsAvg + Math.log10(intens)
                            tmp_maxIntensity = (tmp_maxIntensity>=intens)?tmp_maxIntensity:intens
                        }
                        tmp_Avg = tmp_Avg + tmp_clsAvg
                        tmpAvgCount = tmpAvgCount + clsValues.intensities.size()
                        tmp_result.cls[cls].put('avg', (tmp_clsAvg/clsValues.intensities.size()))
                    }
                    tmp_result.put('avg', (tmp_Avg/tmpAvgCount))
                    tmp_result.put('max', tmp_maxIntensity)
                    tmp_result.put('nrOfCelllines', tmpAvgCount)
                    if(true){
                        def tmp_refAvg = (refLine=='avg')?tmp_result.avg:tmp_result.cls[refLine].avg
                        tmp_result.cls.each{cls, clsValues->
                            clsValues.put('regulation', (((Math.log10(clsValues.avg/tmp_refAvg)/Math.log10(2))*100).toInteger()/100))
                            if(clsValues.regulation>=0){
                                upRegulated++
                            }else if(clsValues.regulation<0){
                                downRegulated++
                            }
                        }
                    }
                    if(tmp_result.pValue>0.05){
                        nonRegulated++
                    }
                    result.add(tmp_result)
            }
        }
        def colors = helperService.getParameters('celllinecolors').celllinecolors
        render(template:'regulationPlots', model:[Projects:result, Non:nonRegulated, Up:upRegulated, Down:downRegulated, RefLine:refLine, QueriedCelllines:queryCelllines, Protein:protein, Colors:colors])
    }

}

